package com.joker.aigc.chat.consumer;


import cn.hutool.core.collection.CollUtil;
import com.joker.aigc.chat.dao.RoomDao;
import com.joker.aigc.chat.domain.dto.PushMessageDTO;
import com.joker.aigc.chat.domain.entity.MQConstant;
import com.joker.aigc.chat.domain.entity.Message;
import com.joker.aigc.chat.domain.entity.Room;
import com.joker.aigc.chat.domain.entity.RoomFriend;
import com.joker.aigc.chat.domain.entity.websocket.WebSocketBaseVo;
import com.joker.aigc.chat.domain.entity.websocket.WebSocketMessageSendStringVo;
import com.joker.aigc.chat.domain.entity.websocket.WebSocketMessageSendVo;
import com.joker.aigc.chat.domain.enums.RoomTypeEnum;
import com.joker.aigc.chat.domain.enums.WebSocketPushTypeEnum;
import com.joker.aigc.chat.domain.enums.WebSocketVoTypeEnum;
import com.joker.aigc.chat.mapper.GroupMemberMapper;
import com.joker.aigc.chat.mapper.MessageMapper;
import com.joker.aigc.chat.service.PushService;
import com.joker.aigc.chat.service.RoomFriendService;
import com.joker.aigc.chat.service.RoomGroupService;
import com.joker.aigc.chat.service.SocketService;
import com.rabbitmq.client.Channel;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * Description:
 * Author: <a href="https://github.com/zongzibinbin">abin</a>
 * Date: 2023-08-12
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MessageConsumer {

    final SocketService webSocketService;
    final RoomDao roomDao;
    final PushService pushService;
    final GroupMemberMapper groupMemberMapper;
    final MessageMapper messageMapper;
    final RoomGroupService roomGroupService;
    final RoomFriendService roomFriendService;

    @SneakyThrows
    @RabbitListener(ackMode = "MANUAL", bindings =
    @QueueBinding(value = @Queue(value = MQConstant.MESSAGE_QUEUE, durable = "true"),
            exchange = @Exchange(value = MQConstant.MESSAGE_EXANGE, type = ExchangeTypes.TOPIC),
            key = MQConstant.MESSAGE_QUEUE + ".*")
    )
    public void onMessage(PushMessageDTO msg, Channel channel, org.springframework.amqp.core.Message message) {
        // 消费完毕。然后确认消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        // 这个是构造消息类型
        log.info("消息被消费 推送至web后端: websocket类型:{}-->{}", WebSocketVoTypeEnum.of(msg.getWsBaseMsg().getType()).getDesc(), msg);
        // 获取推送类型。第一
        WebSocketPushTypeEnum wsPushTypeEnum = WebSocketPushTypeEnum.of(msg.getPushType());
        if (wsPushTypeEnum != null) {
            // 开始推送消息
            List<Long> uids = msg.getUidList();
            switch (wsPushTypeEnum) {
                case USER:
                    if (CollUtil.isNotEmpty(uids)) {
                        uids.forEach(uid -> webSocketService.sendToUid(msg.getWsBaseMsg(), uid));
                    }
                    break;
                case ALL:
                    Long uid = null;
                    if (CollUtil.isNotEmpty(msg.getUidList())) {
                        uid = msg.getUidList().get(0);
                    }
                    webSocketService.sendToAllOnline(msg.getWsBaseMsg(), uid);
                    break;
            }
        }

    }


    @SneakyThrows
    @RabbitListener(ackMode = "MANUAL", autoStartup = "true",
            bindings = @QueueBinding(value = @Queue(value = MQConstant.WEBSOCKET_QUEUE, durable = "true"),
                    exchange = @Exchange(value = MQConstant.WEBSOCKET_EXCHANHE, type = ExchangeTypes.TOPIC),
                    key = {"message"})
    )
    public void message(WebSocketBaseVo<WebSocketMessageSendVo> msg, Channel channel, org.springframework.amqp.core.Message message) {
        log.info("推送消息至rabbitmq:{}", msg);
        // 消费完毕。然后确认消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

        // 这边是消息
        WebSocketMessageSendVo socketMessageSendVo = msg.getData();
        Long msgId = socketMessageSendVo.getMsgId();
        // 如果消息存在
        if (msgId != null) {
            // 查找到消息类型。
            Message chatMessage = messageMapper.selectById(msgId);
            // 构建发送消息。这里传递的都是 string .因为 long 基本上前端都存储不下。只能替换成string
            WebSocketMessageSendStringVo sendStringVo = new WebSocketMessageSendStringVo();
            sendStringVo.setRoomId(String.valueOf(chatMessage.getId()));
            sendStringVo.setRoomId(String.valueOf(chatMessage.getRoomId()));
            sendStringVo.setFromUid(String.valueOf(chatMessage.getFromUid()));
            WebSocketBaseVo<WebSocketMessageSendStringVo> send = new WebSocketBaseVo<>();
            send.setType(WebSocketVoTypeEnum.MESSAGE.getType());
            send.setData(sendStringVo);

            // 根据message 找到
            Room room = roomDao.getById(chatMessage.getRoomId());
            RoomTypeEnum roomTypeEnum = RoomTypeEnum.of(room.getType());
            if (roomTypeEnum == RoomTypeEnum.GROUP) {
                // 如果是
                if (room.isHotRoom()) {
                    // 推送给所有在线人员
                    pushService.sendWebSocketAll(send, chatMessage.getFromUid());
                } else {
                    // 如果是群聊的话，那我就得吧这个消息发送给所有这个群里的人
                    List<Long> uids = groupMemberMapper.selectUserIdByRoomId(room.getId());
                    pushService.sendWebSocket(send, uids);
                }
            } else {
                // 如果是单聊的话，则推送给个人
                // 查找到房间信息
                RoomFriend roomFriend = roomFriendService.getRoomFriendByRoomId(room.getId());
                Long uid = roomFriendService.getFriendUid(roomFriend, chatMessage.getFromUid());
                pushService.sendWebSocket(send, uid);
            }
        }

    }

}
